package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面类，用于实现公共字段的自动填充处理逻辑。
 */
@Aspect // 表明这是一个切面类
@Component // 将该类作为一个 Spring 组件注册到上下文中
@Slf4j // 自动生成一个 Logger 对象，用于日志记录
public class AutoFillAspect {

    /**
     * 定义切入点，匹配所有在 com.sky.mapper 包下的类中的方法
     * 且这些方法被 @AutoFill 注解标记。
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {
        // 此方法体为空，切入点的定义在上方表达式中
    }

    /**
     * 在切入点匹配的方法执行之前，会执行这个增强逻辑。
     *
     * @param joinPoint 切入点信息，包括方法执行信息
     */
    @Before("autoFillPointCut()") // 在 autoFillPointCut 指定的切入点之前执行
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始自动填充..."); // 记录日志，指示开始自动填充公共字段的操作

        // 获取正在执行的方法签名，帮助获取被注解的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取 @AutoFill 注解
        AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);
        // 获取操作类型（插入或更新）
        OperationType operationType = autoFill.value();

        // 获取切入点的参数
        Object[] args = joinPoint.getArgs();
        if (args == null || args.length == 0) {
            return; // 如果没有参数，直接返回
        }
        Object entity = args[0]; // 获取第一个参数，通常为要填充的实体

        LocalDateTime now = LocalDateTime.now(); // 当前时间
        Long currentId = BaseContext.getCurrentId(); // 获取当前用户的ID

        if (operationType == OperationType.INSERT) {
            // 插入操作需要设置创建时间和创建用户
            try {
                // 使用反射获取设置字段的方法
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                // 设置相应的值
                setCreateTime.invoke(entity, now);
                setCreateUser.invoke(entity, currentId);
                setUpdateTime.invoke(entity, now);
                setUpdateUser.invoke(entity, currentId);

            } catch (Exception e) {
                e.printStackTrace(); // 异常处理，打印堆栈跟踪
            }

        } else if (operationType == OperationType.UPDATE) {
            // 更新操作只需要更新用户和更新时间
            try {
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                // 设置更新时间和更新用户
                setUpdateTime.invoke(entity, now);
                setUpdateUser.invoke(entity, currentId);

            } catch (Exception e) {
                e.printStackTrace(); // 异常处理，打印堆栈跟踪
            }
        }
    }
}